package symbol;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import translationTable.Data;
import translationTable.Data.DataException;
import translationTable.Data.DataUnableToSwitchToCorrectXMLFileStream;

/**
 * This is an entry in the symbol table.
 */
public class SymbolTableEntry {

    private Map<Integer, ObjectState> states;
    //the static type of the object (initialized at its declaration)
    private String typeDeclaration;

    public SymbolTableEntry() {
        this.states = new HashMap<Integer, ObjectState>();
    }

    public SymbolTableEntry(String typeDeclaration) {
        this();
        this.typeDeclaration = typeDeclaration.replaceAll("\\s", "");
    }

    public void add(Integer instrNum, ObjectState state)            
            throws DataUnableToSwitchToCorrectXMLFileStream, DataException, SymbolTableEntryException {
        
        boolean aTraduire=true;
        ArrayList<String> typePrimitif = new ArrayList<String>();
        typePrimitif.add("byte");
        typePrimitif.add("short");
        typePrimitif.add("int");
        typePrimitif.add("int");
        typePrimitif.add("long");
        typePrimitif.add("float");
        typePrimitif.add("double");
        typePrimitif.add("char");
        typePrimitif.add("boolean");        
        
        
        if (state != null) {
            String effectiveType = state.getType().replaceAll("\\s", ""); 
            
            typeDeclaration = typeDeclaration.replaceAll("\\s", "");            
            for (String str : typePrimitif){
                if(str.equals(typeDeclaration))
                    aTraduire=false;
            }
            
            if (!effectiveType.equals(typeDeclaration)&& aTraduire) {
                List<String> acstrs = Data.getInstance().getAncestors(effectiveType, Data.MADKIT);
                boolean correctDeclaration = false;                
                
                for (String acstr : acstrs) {
                    acstr = acstr.replaceAll("\\s", "");                    
                    if (acstr.equals(typeDeclaration)) {                        
                        correctDeclaration = true;
                        break;
                    }
                }
                
                if (!correctDeclaration) {
                    throw new SymbolTableEntryException("Invalid declaration, the specified declaration type does not match to any of the possible static type.");
                }
            }
            this.states.put(instrNum,state);
            //System.out.println("New state in the symbolTableEntry: "+this.toString());
        }
    }

    public String getTypeDeclaration() {
        return typeDeclaration;
    }

    public void setTypeDeclaration(String typeDeclaration) {
        this.typeDeclaration = typeDeclaration;
    }

    public ObjectState get(Integer instrNum) {
        return this.states.get(instrNum);
    }

    public ObjectState getClosestState(Integer instrNum) {
        int closestInstr = 0;
        for (Entry<Integer, ObjectState> e : this.states.entrySet()) {
            if (e.getKey() > instrNum) {
                break;
            }
            if ((instrNum - e.getKey()) < instrNum - closestInstr) {
                closestInstr = e.getKey();
            }
        }
        return this.states.get(closestInstr);
    }

    public void set(Integer instrNum, ObjectState state) {
        this.states.put(instrNum, state);
    }

    @Override
    public String toString() {
        String toString = "SymbolTableEntry{\n\tstates=";
        for (Entry<Integer, ObjectState> e : this.states.entrySet()) {
            toString += "\t" + e.getKey() + ":" + e.getValue() + "\n";
        }
        toString += ", typeDeclaration=" + typeDeclaration + "\n}";
        return toString;
    }

    public class SymbolTableEntryException extends Exception {

        public SymbolTableEntryException(String msg) {
            super(msg);
        }
    }
}